package hu.myai.controller;

import hu.myai.model.db.AxEstimation;
import hu.myai.runtimeneural.ExecuteNeuralNetwork;
import hu.myai.util.Constans;
import hu.myai.util.DatabaseUtil;
import hu.myai.util.SanfordNet;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.joone.log.ILogger;
import org.joone.log.LoggerFactory;
import org.joone.net.NeuralNet;

public class CreateEstimation {

	private static final ILogger log = LoggerFactory.getLogger(CreateEstimation.class);

	private SanfordNet netUtil = new SanfordNet();;

	private boolean full = true;

	// Type:
	// 1 - get the best out of multiple result
	// 2 - get the average out of multiple result
	// 3 - execute own by own

	private int estimateType = 3;

	// for database util reference
	private DatabaseUtil dbUtil = new DatabaseUtil();

	public CreateEstimation() {
	}

	public void go(String[] fileArray) {

		CreateEstimation thisClass = new CreateEstimation();
		SaveEstimation saveEstimation = new SaveEstimation();

		List<String> nnetList = new ArrayList<String>();
		List<String> symbolList = new ArrayList<String>();

		File file = null;
		for (int i = 0; i < fileArray.length; i++) {
			file = new File(fileArray[i]);
			if (file.isFile() && file.length() > 0 && fileArray[i].endsWith(".snet"))
				nnetList.add(fileArray[i]);
			else if (fileArray[i].indexOf(".") == -1)
				symbolList.add(fileArray[i]);
		}

		// if not even one given over, it makes it all
		if (symbolList.size() == 0) {
			String forCheckSymbol = Constans.forCheckSymbol.replaceAll("[ \t\n]+", " ");
			String[] symbolArray = forCheckSymbol.split(" ");

			for (int i = 0; i < symbolArray.length; i++) {
				symbolList.add(symbolArray[i]);
			}
		}

		// if not netfiles give
		File nnetFilesDir = new File(Constans.nnetFilesDir);
		if (nnetList.size() == 0 && nnetFilesDir.isDirectory()) {

			// all symbol x all nnetFile
			if (full) {
				// iterate thru symbol folders

				File[] nnetFile = nnetFilesDir.listFiles();
				for (int i = 0; i < nnetFile.length; i++) {

					// get the saved nets recursively!
					if (nnetFile[i].isDirectory()) {
						// iterate thru contents of folder
						String[] dirContainer = nnetFile[i].list();
						for (int j = 0; j < dirContainer.length; j++) {
							if (dirContainer[j].toLowerCase().endsWith(".snet")) {
								nnetList.add(nnetFile[i].getAbsoluteFile() + File.separator + dirContainer[j]);
								// break;
							}
						}
					} else {
						if (nnetFile[i].getName().toLowerCase().endsWith(".snet")) {
							nnetList.add(nnetFile[i].getAbsolutePath());
						}
					}
				}
			}
		} else {
			log.error("Error - Constans is wrong, nnetFilesDir is not a directory.");
		}

		List<HistoryComp> resultList = new ArrayList<HistoryComp>();

		symbol: for (String symbol : symbolList) {

			AxEstimation bestEstimation = new AxEstimation();
			double[][] historyArray = dbUtil.getHistoryForExecute(SanfordNet.getStartDate(), symbol);

			List<HistoryComp> resultSubList = new ArrayList<HistoryComp>();

			// symbol = nnetfile of symbol
			if (!full)
				nnetList = netUtil.getNnetFiles(symbol);

			for (String nnetFile : nnetList) {

				// overwrite actual symbol for make more fast calculation for
				// this special 3 case
				if (estimateType == 3) {
					symbol = nnetFile.substring(nnetFile.lastIndexOf(File.separator) + 1, nnetFile.indexOf("_",
							nnetFile.lastIndexOf(File.separator)));
					historyArray = dbUtil.getHistoryForExecute(SanfordNet.getStartDate(), symbol);
				}

				log.info("Symbol: " + symbol);
				log.info("NN file: " + nnetFile);

				// restore net from file
				NeuralNet nnet = netUtil.restoreNeuralNet(nnetFile);

				ExecuteNet sampleNet = thisClass.new ExecuteNet(nnet);

				if (nnet != null) {
					try {

						sampleNet.Go(symbol, nnetFile, historyArray);
						sampleNet.nnet.join();
					} catch (Exception ex) {
						ex.printStackTrace();
						if (estimateType != 3)
							continue symbol;
						else
							continue;
					}
					AxEstimation resultEstimation = sampleNet.estimation;

					if (resultEstimation == null) {
						log.error("Error - no estimation: " + symbol + "  " + nnetFile);
						continue;
					}

					// take consider of the best net
					if (estimateType == 1) {

						if (bestEstimation.getError() > resultEstimation.getError())
							bestEstimation = resultEstimation;
					} else
					// get the average
					if (estimateType == 2) {

						resultSubList.add(new HistoryComp(resultEstimation));
						bestEstimation = resultEstimation;
					} else
					// get own by own
					if (estimateType == 3) {

						if (resultEstimation.getNnet().startsWith(symbol))
							saveEstimation.saveAxEstimation(resultEstimation);
						resultList.add(new HistoryComp(resultEstimation));
						dbUtil.entityManager.clear();
					}

				} else {
					log.error("Error: " + nnetFile + " file is not valid");
					continue;
				}
			}

			// save the best estimation
			if (bestEstimation != null) {
				if (estimateType == 1) {

					resultList.add(new HistoryComp(bestEstimation));
					saveEstimation.saveAxEstimation(bestEstimation);

				} else
				// get the average
				if (estimateType == 2) {

					double est1 = 0;
					double est2 = 0;
					double est3 = 0;
					double err = 0;

					int i = 0;
					for (; i < resultSubList.size(); i++) {
						est1 += resultSubList.get(i).est1;
						est2 += resultSubList.get(i).est2;
						est3 += resultSubList.get(i).est3;
						err += resultSubList.get(i).err;
					}
					est1 /= resultSubList.size();
					est2 /= resultSubList.size();
					est3 /= resultSubList.size();
					err /= resultSubList.size();

					bestEstimation.setEstimation1(est1);
					bestEstimation.setEstimation2(est2);
					bestEstimation.setEstimation3(est3);
					bestEstimation.setError(err);
					bestEstimation.setNnet(null);

					resultList.add(new HistoryComp(bestEstimation));
					saveEstimation.saveAxEstimation(bestEstimation);
				}
			}
			dbUtil.entityManager.clear();

			if (estimateType == 3)
				break;

		}

		Collections.sort(resultList);

		for (HistoryComp rec : resultList) {
			System.out.println(rec.toString());
		}
	}

	public void go() {
		go(new String[0]);
	}

	public class ExecuteNet extends ExecuteNeuralNetwork {
		public ExecuteNet(NeuralNet nnet) {
			super(nnet);
		}
	}

	public class HistoryComp implements Comparable<HistoryComp> {
		public String symbol;

		public double est1;

		public double est2;

		public double est3;

		public double err;

		public HistoryComp(AxEstimation e) {
			this.symbol = e.get_symbol();
			this.est1 = e.getEstimation1();
			this.est2 = e.getEstimation2();
			this.est3 = e.getEstimation3();
			this.err = e.getError();
		}

		public int compareTo(HistoryComp c) {
			return est1 - c.est1 > 0 ? 1 : -1;
		}

		@Override
		public String toString() {
			return "Symbol: " + symbol + " buy/sell:" + netUtil.trim(est1) + " Est2:" + netUtil.trim(est2) + " Est3:"
					+ netUtil.trim(est3) + " err:" + netUtil.trim(err);
		}
	}
}
